<?php
/**
 * Created by PhpStorm
 * User: Jhinwy
 * Date: 9/5/24
 * Time: 5:37 PM
 */

namespace app\common\service\douyin;

use app\common\model\app\App;
use GuzzleHttp\Client;
use think\facade\Cache;
use think\facade\Log;

class DouyinService
{

    const CACHE_DOUYIN_MINI_PROGRAM_ACCESS_TOKEN = 'douyin_mini_program_access_token_';


    protected static $host = 'https://open.douyin.com/';

    protected static $headers = ['Content-Type' => 'application/json'];

    protected static $accessTokenUri = 'oauth/client_token/';
    protected static $uploadUri      = 'api/playlet/v2/resource/upload/';
    protected static $createVideoUri = 'api/playlet/v2/video/create/';
    protected static $queryVideoUri  = 'api/playlet/v2/video/query/';
    protected static $editVideoUri   = 'api/playlet/v2/video/edit/';
    protected static $reviewVideoUri = 'api/playlet/v2/video/review/';
    protected static $albumOnlineUri = 'api/playlet/v2/album/online/';
    protected static $fetchAlbumUri  = 'api/playlet/v2/album/fetch/';
    protected static $authAlbumUri   = 'api/playlet/v2/auth/authorize/';


    public static function getAccessToken($appId)
    {
        try {
            if ($accessToken = Cache::get(self::CACHE_DOUYIN_MINI_PROGRAM_ACCESS_TOKEN . $appId)) {

                return $accessToken;
            }
            $app       = App::where('app_id', $appId)->findOrEmpty();
            $appSecret = $app->app_secret ?? '';
            $client    = new Client();
            $response  = $client->post(
                self::formatUrl(self::$accessTokenUri),
                self::formatData([
                    'client_key'    => $appId,
                    'client_secret' => $appSecret,
                    'grant_type'    => 'client_credential'
                ])
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents    = $response->getBody()->getContents();
            $result      = json_decode($contents, true);
            $data        = $result['data'] ?? [];
            $accessToken = $data['access_token'] ?? '';
            $expiresIn   = $data['expires_in'] ?? 0;
            if (!$accessToken || !$expiresIn) {
                throw new \Exception('token信息不存在');
            }
            Cache::set(self::CACHE_DOUYIN_MINI_PROGRAM_ACCESS_TOKEN . $appId, $accessToken, $expiresIn);

            return $accessToken;
        } catch (\Exception $exception) {
            Log::write('获取抖音小程序Access Token失败：' . $exception->getMessage());

            return false;
        }
    }


    /**
     * 上传图片
     *
     * @param $appId
     * @param $picUrl
     * @return mixed|string
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function uploadPic($appId, $picUrl)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client   = new Client();
            $response = $client->post(
                self::formatUrl(self::$uploadUri),
                self::formatData([
                    'resource_type' => 2,
                    'ma_app_id'     => $appId,
                    'image_meta'    => ['url' => $picUrl]
                ], $accessToken)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents    = $response->getBody()->getContents();
            $result      = json_decode($contents, true);
            $data        = $result['data'] ?? [];
            $imageResult = $data['image_result'] ?? [];

            return $imageResult['open_pic_id'] ?? '';
        } catch (\Exception $exception) {
            Log::write('上传抖音图片失败：' . $exception->getMessage());

            return '';
        }
    }


    /**
     * 创建抖音短剧
     *
     * @param $appId
     * @param $data
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function createVideo($appId, $data)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client = new Client();
            Log::write('创建抖音短剧：' . json_encode($data));
            $response = $client->post(
                self::formatUrl(self::$createVideoUri),
                self::formatData([
                    'resource_type' => 2,
                    'ma_app_id'     => $appId,
                    'album_info'    => $data
                ], $accessToken)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);
            if ($result['err_no'] != 0) {
                throw new \Exception($result['err_msg']);
            }
            $data = $result['data'] ?? [];

            return ['err_code' => 0, 'album_id' => $data['album_id'] ?? ''];
        } catch (\Exception $exception) {
            Log::write('创建抖音短剧失败：' . $exception->getMessage());

            return ['err_code' => -1, 'msg' => '创建抖音短剧失败：' . $exception->getMessage()];
        }
    }


    /**
     * 上传视频
     *
     * @param $appId
     * @param $videoUrl
     * @param $title
     * @param $format
     * @param bool $useDyCloud
     * @param string $dyCloudId
     * @return mixed|string
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function uploadVideo($appId, $videoUrl, $title, $format, $useDyCloud = true, $dyCloudId = '')
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client    = new Client();
            $videoData = [
                'url'          => $videoUrl,
                'title'        => $title,
                'format'       => $format,
                'use_dy_cloud' => $useDyCloud,
            ];
            if ($dyCloudId) {
                $videoData['dy_cloud_id'] = $dyCloudId;
            }

            $response = $client->post(
                self::formatUrl(self::$uploadUri),
                self::formatData([
                    'resource_type' => 1,
                    'ma_app_id'     => $appId,
                    'video_meta'    => $videoData
                ], $accessToken)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            Log::write('上传抖音视频3333：' . $contents);

            $result      = json_decode($contents, true);
            $data        = $result['data'] ?? [];
            $videoResult = $data['video_result'] ?? [];

            return $videoResult['open_video_id'] ?? '';
        } catch (\Exception $exception) {
            Log::write('上传抖音视频失败：' . $exception->getMessage());

            return '';
        }
    }


    /**
     * 编辑短剧/添加剧集
     *
     * @param $appId
     * @param $albumId
     * @param array $albumInfo
     * @param array $episodeInfoList
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function editVideo($appId, $albumId, $albumInfo = [], $episodeInfoList = [])
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client = new Client();
            $data   = [
                'ma_app_id' => $appId,
                'album_id'  => $albumId,
            ];
            if ($albumInfo) {
                $data['album_info'] = $albumInfo;
            }
            if ($episodeInfoList) {
                $data['episode_info_list'] = $episodeInfoList;
            }
            Log::write('编辑短剧/添加剧集1111：' . json_encode($data));
            $response = $client->post(
                self::formatUrl(self::$editVideoUri),
                self::formatData($data, $accessToken)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            Log::write('编辑短剧2222：' . $contents);
            $result = json_decode($contents, true);
            if ($result['err_no'] != 0) {
                throw new \Exception($result['err_msg']);
            }
            $data = $result['data'] ?? [];

            return ['err_code' => 0, 'data' => $data];
        } catch (\Exception $exception) {
            Log::write('编辑短剧/添加剧集失败：' . $exception->getMessage());

            return ['err_code' => -1, 'msg' => '编辑短剧/添加剧集失败：' . $exception->getMessage()];
        }
    }


    /**
     * 查询剧集视频状态
     *
     * @param $appId
     * @param $open_video_id
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function queryVideo($appId, $open_video_id)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client   = new Client();
            $response = $client->post(
                self::formatUrl(self::$queryVideoUri),
                self::formatData([
                    'video_id_type' => 1,
                    'ma_app_id'     => $appId,
                    'open_video_id' => $open_video_id
                ], $accessToken)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);
            if ($result['err_no'] != 0) {
                throw new \Exception($result['err_msg']);
            }
            $data = $result['data'] ?? [];

            return ['err_code' => 0, 'album_id' => $data['album_id'] ?? ''];
        } catch (\Exception $exception) {
            Log::write('查询视频剧集失败：' . $exception->getMessage());

            return ['err_code' => -1, 'msg' => '查询视频剧集失败：' . $exception->getMessage()];
        }
    }


    /**
     * 获取剧集信息
     *
     * @param $appId
     * @param $queryType - 1：查询小程序下所有短剧信息- 2：查询一个短剧所有版本信息- 3：查询一个短剧某个版本下所有剧集信息 默认查询剧集信息同步
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function fetchAlbum($appId, $albumId = '', $version = 1, $offset = 0, $queryType = 3)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client = new Client();
            $data   = [
                'ma_app_id'  => $appId,
                'query_type' => $queryType,
            ];
            switch ($queryType) {
                case 1 :
                    $data['batch_query'] = ['offset' => $offset, 'limit' => 50];
                    break;
                case 2 :
                    $data['single_query'] = ['offset' => $offset, 'limit' => 50, 'album_id' => $albumId];
                    break;
                case 3 :
                    $data['detail_query'] = ['offset' => $offset, 'limit' => 50, 'album_id' => $albumId, 'version' => $version];
                    break;
            }

            $response = $client->post(
                self::formatUrl(self::$fetchAlbumUri),
                self::formatData($data, $accessToken)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);
            if ($result['err_no'] != 0) {
                throw new \Exception($result['err_msg']);
            }
            $data         = $result['data'] ?? [];
            $detailData   = $data['detail_data'] ?? [];
            $total        = $detailData['total'] ?? 0;
            $episodesList = $detailData['episode_info_list'] ?? [];
            $list         = [];
            foreach ($episodesList as $item) {
                if (!$episodesInfo = $item['episode_audit_info'] ?? []) {
                    continue;
                }
                $list[] = [
                    'episode_id'    => $episodesInfo['episode_id'] ?? '',
                    'open_video_id' => $item['open_video_id'] ?? '',
                    'seq'           => $item['seq'] ?? 1,
                    'title'         => $item['title'] ?? ''
                ];
            }

            return $list;
        } catch (\Exception $exception) {
            Log::write('【同步】获取短剧剧集失败：' . $exception->getMessage());

            return ['err_code' => -1, 'msg' => '【同步】获取短剧剧集失败：' . $exception->getMessage()];
        }
    }


    /**
     * 抖音短剧送审
     *
     * @param $appId
     * @param $albumId
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function reviewVideo($appId, $albumId)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client   = new Client();
            $response = $client->post(
                self::formatUrl(self::$reviewVideoUri),
                self::formatData([
                    'ma_app_id' => $appId,
                    'album_id'  => $albumId
                ], $accessToken)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            Log::write('抖音短剧送审：' . $contents);
            $result = json_decode($contents, true);
            if ($result['err_no'] != 0) {
                throw new \Exception($result['err_msg']);
            }
            $data = $result['data'] ?? [];

            return ['err_code' => 0, 'version' => $data['version'] ?? 0];
        } catch (\Exception $exception) {
            Log::write('抖音短剧送审失败：' . $exception->getMessage());

            return ['err_code' => -1, 'msg' => '抖音短剧送审失败：' . $exception->getMessage()];
        }
    }


    /**
     * 抖音短剧上线
     *
     * @param $appId
     * @param $albumId
     * @param $version
     * @param int $operate
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function onlineAlbum($appId, $albumId, $version, $operate = 2)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client   = new Client();
            $response = $client->post(
                self::formatUrl(self::$albumOnlineUri),
                self::formatData([
                    'album_id' => $albumId,
                    'operate'  => $operate,
                    'version'  => $version
                ], $accessToken)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            Log::write('抖音短剧上线：' . $contents);
            $result = json_decode($contents, true);
            if ($result['err_no'] != 0) {
                throw new \Exception($result['err_msg']);
            }

            return true;
        } catch (\Exception $exception) {
            Log::write('抖音短剧上线失败：' . $exception->getMessage());

            return false;
        }
    }


    /**
     * 授权短剧
     *
     * @param $appId
     * @param $albumId
     * @param array $appIdList
     * @param bool $increment
     * @param bool $remove
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function authAlbum($appId, $albumId, $appIdList = [], $increment = true, $remove = false)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client   = new Client();
            $response = $client->post(
                self::formatUrl(self::$authAlbumUri),
                self::formatData([
                    'ma_app_id'   => $appId,
                    'album_id'    => $albumId,
                    'app_id_list' => $appIdList,
                    'increment'   => $increment,
                    'remove'      => $remove
                ], $accessToken)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            Log::write('抖音短剧授权：' . $contents);
            $result = json_decode($contents, true);
            if ($result['err_no'] != 0) {
                throw new \Exception($result['err_msg']);
            }

            return true;
        } catch (\Exception $exception) {
            Log::write('抖音短剧授权失败：' . $exception->getMessage());

            return false;
        }
    }


    /**
     * 格式化数据
     *
     * @param $data
     * @return array
     */
    protected static function formatData($data, $accessToken = '')
    {
        if ($accessToken) {
            self::$headers['access-token'] = $accessToken;
        }
        return [
            'headers' => self::$headers,
            'body'    => json_encode($data, JSON_UNESCAPED_UNICODE)
        ];
    }


    /**
     * 格式化Api
     *
     * @param $uri
     * @return string
     */
    protected static function formatUrl($uri)
    {
        return self::$host . $uri;
    }
}
